package com.open.capacity.utils;

import org.apache.commons.lang3.StringUtils;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoField;
import java.time.temporal.TemporalAdjusters;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;

/**
 * 基于Java8的时间工具类
 *
 * @author keji
 * @version $Id: DateUtil.java, v 0.1 2018-12-28 14:11 keji Exp $
 */
public class DateUtil {

    /**
     * 例如:2018-12-28
     */
    public static final String DATE = "yyyy-MM-dd";

    /**
     * 例如:2018-12-28
     */
    public static final String DATE2 = "yyyyMMdd";
    /**
     * 例如:2018-12-28 10:00:00
     */
    public static final String DATE_TIME = "yyyy-MM-dd HH:mm:ss";
    /**
     * 例如:10:00:00
     */
    public static final String TIME = "HHmmss";
    /**
     * 例如:10:00
     */
    public static final String TIME_WITHOUT_SECOND = "HH:mm";

    /**
     * 例如:2018-12-28 10:00
     */
    public static final String DATE_TIME_WITHOUT_SECONDS = "yyyy-MM-dd HH:mm";

    public static final String YYYYMMDDHHMMSS = "yyyyMMddHHmmss";
    public static final String YYYYMMDD = "yyyyMMdd";

    /**
     * 获取年
     *
     * @return 年
     */
    public static int getYear() {
        LocalDateTime localTime = LocalDateTime.now();
        return localTime.get(ChronoField.YEAR);
    }

    /**
     * 获取年
     *
     * @return 年
     */
    public static int getYear(Date date) {
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        int y = c.get(Calendar.YEAR);
        return y;
    }

    /**
     * 获取月份
     *
     * @return 月份
     */
    public static int getMonth() {
        LocalDateTime localTime = LocalDateTime.now();
        return localTime.get(ChronoField.MONTH_OF_YEAR);
    }

    /**
     * 获取某月的第几天
     *
     * @return 几号
     */
    public static int getMonthOfDay() {
        LocalTime localTime = LocalTime.now();
        return localTime.get(ChronoField.DAY_OF_MONTH);
    }

    /**
     * 格式化日期为字符串
     *
     * @param date date
     * @return 日期字符串
     */
    public static String format(Date date) {

        Instant instant = date.toInstant();

        LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());

        return localDateTime.format(DateTimeFormatter.ofPattern(DATE_TIME));
    }

    /**
     * 获取当前时间
     *
     * @return
     */
    public static final String dateTimeNow() {
        return format(new Date(), YYYYMMDDHHMMSS);
    }

    /**
     * 获取当前日期
     *
     * @return
     */
    public static final String dateNow() {
        return format(new Date(), YYYYMMDD);
    }

    /**
     * 格式化日期为字符串
     *
     * @param date date
     * @return 日期字符串
     */
    public static String formatDate(Date date) {

        Instant instant = date.toInstant();

        LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());

        return localDateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
    }

    /**
     * 格式化日期为字符串
     *
     * @param date    date
     * @param pattern 格式
     * @return 日期字符串
     */
    public static String format(Date date, String pattern) {

        Instant instant = date.toInstant();

        LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());

        return localDateTime.format(DateTimeFormatter.ofPattern(pattern));
    }


    /**
     * 解析字符串日期为Date
     *
     * @param dateStr 日期字符串
     * @return Date
     */
    public static Date parse(String dateStr) {

        LocalDateTime localDateTime = LocalDateTime.parse(dateStr, DateTimeFormatter.ofPattern(DATE_TIME));
        Instant instant = localDateTime.atZone(ZoneId.systemDefault()).toInstant();
        return Date.from(instant);
    }

    /**
     * 解析字符串日期为Date
     *
     * @param dateStr 日期字符串
     * @param pattern 格式
     * @return Date
     */
    public static Date parse(String dateStr, String pattern) {
        LocalDateTime localDateTime = LocalDateTime.parse(dateStr, DateTimeFormatter.ofPattern(pattern));
        Instant instant = localDateTime.atZone(ZoneId.systemDefault()).toInstant();
        return Date.from(instant);
    }

    /**
     * 解析字符串日期为Date
     *
     * @param dateStr 日期字符串
     * @return Date
     */
    public static Date parseDate(String dateStr) {
        LocalDate localDate = LocalDate.parse(dateStr, DateTimeFormatter.ofPattern(DATE));
        Instant instant = localDate.atStartOfDay(ZoneId.systemDefault()).toInstant();
        return Date.from(instant);
    }

    /**
     * 解析字符串日期为Date2
     *
     * @param dateStr 日期字符串
     * @return Date
     */
    public static Date parseDate2(String dateStr) {
        LocalDate localDate = LocalDate.parse(dateStr, DateTimeFormatter.ofPattern(DATE2));
        Instant instant = localDate.atStartOfDay(ZoneId.systemDefault()).toInstant();
        return Date.from(instant);
    }

    /**
     * 解析字符串日期为Date
     *
     * @param dateStr 日期字符串
     * @return Date
     */
    public static Date parseDate(String dateStr, String pattern) {

        LocalDate localDate = LocalDate.parse(dateStr, DateTimeFormatter.ofPattern(pattern));
        Instant instant = localDate.atStartOfDay(ZoneId.systemDefault()).toInstant();
        return Date.from(instant);
    }


    /**
     * 为Date增加分钟,减传负数
     *
     * @param date        日期
     * @param plusMinutes 要增加的分钟数
     * @return 新的日期
     */
    public static Date addMinutes(Date date, Long plusMinutes) {
        LocalDateTime dateTime = LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault());
        LocalDateTime newDateTime = dateTime.plusMinutes(plusMinutes);
        return Date.from(newDateTime.atZone(ZoneId.systemDefault()).toInstant());
    }

    /**
     * 增加时间
     *
     * @param date date
     * @param hour 要增加的小时数
     * @return new date
     */
    public static Date addHour(Date date, Long hour) {
        LocalDateTime dateTime = LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault());
        LocalDateTime localDateTime = dateTime.plusHours(hour);
        return Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
    }

    /**
     * @return 返回当天的起始时间
     */
    public static Date getStartTime() {

        LocalDateTime now = LocalDateTime.now().withHour(0).withMinute(0).withSecond(0);
        return localDateTime2Date(now);
    }


    /**
     * @return 返回当天的结束时间
     */
    public static Date getEndTime() {
        LocalDateTime now = LocalDateTime.now().withHour(23).withMinute(59).withSecond(59).withNano(999);
        return localDateTime2Date(now);
    }

    /**
     * 减月份
     *
     * @param monthsToSubtract 月份
     * @return Date
     */
    public static Date minusMonths(long monthsToSubtract) {
        LocalDate localDate = LocalDate.now().minusMonths(monthsToSubtract);

        return localDate2Date(localDate);
    }

    /**
     * LocalDate类型转为Date
     *
     * @param localDate LocalDate object
     * @return Date object
     */
    public static Date localDate2Date(LocalDate localDate) {

        ZonedDateTime zonedDateTime = localDate.atStartOfDay(ZoneId.systemDefault());

        return Date.from(zonedDateTime.toInstant());
    }

    /**
     * LocalDateTime类型转为Date
     *
     * @param localDateTime LocalDateTime object
     * @return Date object
     */
    public static Date localDateTime2Date(LocalDateTime localDateTime) {
        return Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
    }

    /**
     * 查询当前年的第一天
     *
     * @param pattern 格式，默认格式yyyyMMdd
     * @return 20190101
     */
    public static String getFirstDayOfCurrentYear(String pattern) {
        LocalDateTime localDateTime = LocalDateTime.now().withMonth(1).withDayOfMonth(1);

        if (StringUtils.isEmpty(pattern)) {
            pattern = "yyyyMMdd";
        }

        return format(localDateTime2Date(localDateTime), pattern);
    }


    /**
     * 查询当前年的最后一天
     *
     * @param pattern 格式，默认格式yyyyMMdd
     * @return 20190101
     */
    public static String getLastDayOfCurrentYear(String pattern) {
        LocalDateTime localDateTime = LocalDateTime.now().withMonth(12).withDayOfMonth(31);

        if (StringUtils.isEmpty(pattern)) {
            pattern = "yyyyMMdd";
        }

        return format(localDateTime2Date(localDateTime), pattern);
    }

    /**
     * 查询前一年最后一个月第一天
     *
     * @param pattern 格式，默认格式yyyyMMdd
     * @return 20190101
     */
    public static String getLastMonthFirstDayOfPreviousYear(String pattern) {
        LocalDateTime localDateTime = LocalDateTime.now().minusYears(1L).withMonth(12).withDayOfMonth(1);

        if (StringUtils.isEmpty(pattern)) {
            pattern = "yyyyMMdd";
        }

        return format(localDateTime2Date(localDateTime), pattern);
    }

    /**
     * 查询前一年最后一个月最后一天
     *
     * @param pattern 格式，默认格式yyyyMMdd
     * @return 20191231
     */
    public static String getLastMonthLastDayOfPreviousYear(String pattern) {
        LocalDateTime localDateTime = LocalDateTime.now().minusYears(1L).with(TemporalAdjusters.lastDayOfYear());

        if (StringUtils.isEmpty(pattern)) {
            pattern = "yyyyMMdd";
        }

        return format(localDateTime2Date(localDateTime), pattern);
    }

    /**
     * 查询当月第一天
     */
    public static String getFirstDayOfMonth(String pzrq) {
        Calendar c = Calendar.getInstance();
        c.setTime(DateUtil.parseDate(pzrq));
        c.add(Calendar.MONTH, 0);
        c.set(Calendar.DAY_OF_MONTH, 1);//设置为1号,当前日期既为本月第一天
        return DateUtil.formatDate(c.getTime());
    }

    /**
     * 查询当月最后一天
     */
    public static String getLastDayOfMonth(String pzrq) {
        Calendar c = Calendar.getInstance();
        c.setTime(DateUtil.parseDate(pzrq));
        c.set(Calendar.DAY_OF_MONTH, c.getActualMaximum(Calendar.DAY_OF_MONTH));
        return DateUtil.formatDate(c.getTime());
    }


    /**
     * 查询当月最后一天
     */
    public static String getLastDayOfMonth(int year, int month) {
        Calendar cal = Calendar.getInstance();
        //设置年份
        cal.set(Calendar.YEAR, year);
        //设置月份
        cal.set(Calendar.MONTH, month - 1);
        //获取某月最大天数
        int lastDay = cal.getActualMaximum(Calendar.DAY_OF_MONTH);
        //设置日历中月份的最大天数
        cal.set(Calendar.DAY_OF_MONTH, lastDay);
        //格式化日期
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        String lastDayOfMonth = sdf.format(cal.getTime());

        return lastDayOfMonth;
    }

    /**
     * 查询当月第一天
     */
    public static String getFirstDayOfMonth(int year, int month) {
        Calendar cal = Calendar.getInstance();
        //设置年份
        cal.set(Calendar.YEAR, year);
        //设置月份
        cal.set(Calendar.MONTH, month - 1);
        //设置日历中月份的最大天数
        cal.set(Calendar.DAY_OF_MONTH, 1);
        //格式化日期
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        String firstDayOfMonth = sdf.format(cal.getTime());

        return firstDayOfMonth;
    }

    /**
     * 获取当前日期
     *
     * @param pattern 格式，默认格式yyyyMMdd
     * @return 20190101
     */
    public static String getCurrentDay(String pattern) {
        LocalDateTime localDateTime = LocalDateTime.now();

        if (StringUtils.isEmpty(pattern)) {
            pattern = "yyyyMMdd";
        }

        return format(localDateTime2Date(localDateTime), pattern);
    }

    /**
     * 计算时间差
     *
     * @param date1
     * @param date2
     * @return
     */
    public static int getBetweenDay(Date date1, Date date2) {
        Calendar d1 = new GregorianCalendar();
        d1.setTime(date1);
        Calendar d2 = new GregorianCalendar();
        d2.setTime(date2);
        int days = d2.get(Calendar.DAY_OF_YEAR) - d1.get(Calendar.DAY_OF_YEAR);
        int y2 = d2.get(Calendar.YEAR);
        if (d1.get(Calendar.YEAR) != y2) {
            do {
                days += d1.getActualMaximum(Calendar.DAY_OF_YEAR);
                d1.add(Calendar.YEAR, 1);
            } while (d1.get(Calendar.YEAR) != y2);
        }
        if (days == 0) {
            days = 1;
        } else {
            days += 1;
        }
        return days;
    }

    /**
     * 计算时间差
     *
     * @param startTime
     * @param endTime
     * @param str
     * @return
     */
    public static Long dateDiff(Date startTime, Date endTime, String str) {
        // 按照传入的格式生成一个simpledateformate对象
        long nd = 1000 * 24 * 60 * 60;// 一天的毫秒数
        long nh = 1000 * 60 * 60;// 一小时的毫秒数
        long nm = 1000 * 60;// 一分钟的毫秒数
        long ns = 1000;// 一秒钟的毫秒数
        long diff;
        long day = 0;
        long hour = 0;
        long min = 0;
        long sec = 0;
        // 获得两个时间的毫秒时间差异
        diff = endTime.getTime() - startTime.getTime();
        day = diff / nd;// 计算差多少天
        hour = diff % nd / nh + day * 24;// 计算差多少小时
        min = diff % nd % nh / nm + day * 24 * 60;// 计算差多少分钟
        sec = diff % nd % nh % nm / ns;// 计算差多少秒
        // 输出结果
//        System.out.println("时间相差：" + day + "天" + (hour - day * 24) + "小时"
//                + (min - day * 24 * 60) + "分钟" + sec + "秒。");
//        System.out.println("hour=" + hour + ",min=" + min);
        if (str.equalsIgnoreCase("h")) {
            return hour;
        } else if (str.equalsIgnoreCase("d")) {
            return day;
        } else {
            return min;
        }
    }


    /**
     * 查询下一个月 (yyyy-MM)
     */
    public static String getNextMonth(String currentMonth) {
        String year = currentMonth.substring(0, 4);
        String month = currentMonth.substring(5, 7);
        String newMonth = "";
        if (month.equals("01")) {
            newMonth = year + "-02";
        } else if (month.equals("02")) {
            newMonth = year + "-03";
        } else if (month.equals("03")) {
            newMonth = year + "-04";
        } else if (month.equals("04")) {
            newMonth = year + "-05";
        } else if (month.equals("05")) {
            newMonth = year + "-06";
        } else if (month.equals("06")) {
            newMonth = year + "-07";
        } else if (month.equals("07")) {
            newMonth = year + "-08";
        } else if (month.equals("08")) {
            newMonth = year + "-09";
        } else if (month.equals("09")) {
            newMonth = year + "-10";
        } else if (month.equals("10")) {
            newMonth = year + "-11";
        } else if (month.equals("11")) {
            newMonth = year + "-12";
        } else if (month.equals("12")) {
            newMonth = (Integer.parseInt(year) + 1) + "-01";
        }
        return newMonth;
    }

    /**
     * 查询上个月 (yyyy-MM)
     */
    public static String getPreMonth(String currentMonth) {
        String year = currentMonth.substring(0, 4);
        String month = currentMonth.substring(5, 7);
        String newMonth = "";
        if (month.equals("01")) {
            newMonth = (Integer.parseInt(year) - 1) + "-12";
        } else if (month.equals("02")) {
            newMonth = year + "-01";
        } else if (month.equals("03")) {
            newMonth = year + "-02";
        } else if (month.equals("04")) {
            newMonth = year + "-03";
        } else if (month.equals("05")) {
            newMonth = year + "-04";
        } else if (month.equals("06")) {
            newMonth = year + "-05";
        } else if (month.equals("07")) {
            newMonth = year + "-06";
        } else if (month.equals("08")) {
            newMonth = year + "-07";
        } else if (month.equals("09")) {
            newMonth = year + "-08";
        } else if (month.equals("10")) {
            newMonth = year + "-09";
        } else if (month.equals("11")) {
            newMonth = year + "-10";
        } else if (month.equals("12")) {
            newMonth = (Integer.parseInt(year) - 1) + "-11";
        }
        return newMonth;
    }

    /**
     * 获取指定月的前一月（年）或后一月（年）
     *
     * @param dateStr
     * @param addMonth
     * @return 输入的时期格式为yyyy-MM，输出的日期格式为yyyy-MM
     * @throws Exception
     */
    public static String getMonth(String dateStr, String pattern, int addMonth) {
        try {
            java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat(pattern);
            java.util.Date sourceDate = sdf.parse(dateStr);
            Calendar cal = Calendar.getInstance();
            cal.setTime(sourceDate);
            cal.add(Calendar.MONTH, addMonth);

            java.text.SimpleDateFormat returnSdf = new java.text.SimpleDateFormat(pattern);
            String dateTmp = returnSdf.format(cal.getTime());
            return dateTmp;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return dateStr;
    }
}
